package connect

import (
	"encoding/json"
	"litetalk/config"
	"litetalk/db"
	"litetalk/logic"
	"litetalk/proto"
	"time"

	"github.com/sirupsen/logrus"
)

var logicRpc = &logic.LogicLocal

type Server struct {
	Buckets         []*Bucket
	BucketIdx       int
	WriteWait       time.Duration
	PongWait        time.Duration
	PingPeriod      time.Duration
	MaxMessageSize  int64
	ReadBufferSize  int
	WriteBufferSize int
	BroadcastSize   int
}

var DefaultServer Server

func init() {
	DefaultServer.WriteWait = config.Conf.Server.WriteWait
	DefaultServer.PongWait = config.Conf.Server.PongWait
	DefaultServer.PingPeriod = config.Conf.Server.PingPeriod
	DefaultServer.MaxMessageSize = config.Conf.Server.MaxMessageSize
	DefaultServer.ReadBufferSize = config.Conf.Server.ReadBufferSize
	DefaultServer.WriteBufferSize = config.Conf.Server.WriteBufferSize
	DefaultServer.BroadcastSize = config.Conf.Server.BroadcastSize
}

func (s *Server) Bucket(userId uint) *Bucket {
	idx := userId % uint(s.BucketIdx)
	return s.Buckets[idx]
}

func (s *Server) Operator(msg *proto.Msg, ch *Channel) {
	var result interface{}

	switch msg.Op {
	case proto.OpPong:
	case proto.OpSingleSend, proto.OpGroupSend:
		rep := &proto.SuccessReply{}
		if err := logicRpc.Push(msg, rep); err != nil {
			logrus.Errorf("Call logic.Push error ", err)
			break
		}
	case proto.OpAllUser:
		req := &proto.IMAllUserReq{}
		res := &proto.IMAllUserRes{}
		if err := json.Unmarshal(msg.Msg, req); err != nil {
			logrus.Errorf("%s input error %s", proto.GetString(msg.Op), err)
			break
		}
		s.GetAllUser(req, res)
		result = res
	case proto.OpOnlineUser:
		res := &proto.IMOnlineUserRes{}
		s.GetOnlineUser(nil, res)
		result = res
	case proto.OpDepartment:
		req := &proto.IMDepartReq{}
		res := &proto.IMDepartRes{}
		if err := json.Unmarshal(msg.Msg, req); err != nil {
			logrus.Errorf("%s input error %s", proto.GetString(msg.Op), err)
		}
		if err := logicRpc.Department(req, res); err != nil {
			logrus.Error("Call logic.Department error:", err)
		}
		result = res
	case proto.OpNormalGroupList:
		req := &proto.IMNormalGroupListReq{}
		res := &proto.IMNormalGroupListRes{}
		if err := json.Unmarshal(msg.Msg, req); err != nil {
			logrus.Errorf("%s input error %s", proto.GetString(msg.Op), err)
		}
		if err := logicRpc.NormalGroupList(req, res); err != nil {
			logrus.Error("Call logic.NormalGroupList error:", err)
		}
		result = res
	case proto.OpGroupCreate:
		req := &proto.IMGroupCreateReq{}
		res := &proto.IMGroupCreateRes{}
		if err := json.Unmarshal(msg.Msg, req); err != nil {
			logrus.Errorf("%s input error %s", proto.GetString(msg.Op), err)
		}
		if err := logicRpc.CreateGroup(req, res); err != nil {
			logrus.Error("Call logic.CreateGroup error:", err)
		}
		result = res
	case proto.OpGroupInfoList:
		req := &proto.IMGroupInfoListReq{}
		res := &proto.IMGroupInfoListRes{}
		if err := json.Unmarshal(msg.Msg, req); err != nil {
			logrus.Errorf("%s input error %s", proto.GetString(msg.Op), err)
		}
		if err := logicRpc.GroupsInfo(req, res); err != nil {
			logrus.Error("Call logic.GroupsInfo error:", err)
		}
		result = res
	case proto.OpGroupChangeMember:
		req := &proto.IMGroupChangeMemberReq{}
		res := &proto.IMGroupChangeMemberRes{}
		if err := json.Unmarshal(msg.Msg, req); err != nil {
			logrus.Errorf("%s input error %s", proto.GetString(msg.Op), err)
		}
		if err := logicRpc.GroupChangeMember(req, res); err != nil {
			logrus.Error("Call logic.GroupChangeMember error:", err)
		}
		result = res
	case proto.OpGetMsgList:
		req := &proto.IMGetMsgListReq{}
		res := &proto.IMGetMsgListRes{}
		if err := json.Unmarshal(msg.Msg, req); err != nil {
			logrus.Errorf("%s input error %s", proto.GetString(msg.Op), err)
		}
		if err := logicRpc.GetMessageList(req, res); err != nil {
			logrus.Error("Call logic.GetMessageList error:", err)
		}
		result = res
	case proto.OpGetLatestMsgId:
		req := &proto.IMGetLastestMsgIdReq{}
		res := &proto.IMGetLastestMsgIdRes{}
		if err := json.Unmarshal(msg.Msg, req); err != nil {
			logrus.Errorf("%s input error %s", proto.GetString(msg.Op), err)
		}
		if err := logicRpc.GetLastestMessage(req, res); err != nil {
			logrus.Error("Call logic.GetLastestMessage error:", err)
		}
		result = res
	default:
		logrus.Errorf("connect readTCP unknown operator %d", msg.Op)
	}

	if result != nil {
		body, _ := json.Marshal(result)
		// new ack message, ack operator must be request + 1
		msg := proto.NewMsg(msg.Op+1, body, msg.Seq)
		ch.PushMsg(msg)
	}
}

func (s *Server) GetAllUser(req *proto.IMAllUserReq, res *proto.IMAllUserRes) {
	u := db.IMUser{}
	userList := u.GetAllUser(time.Unix(req.LastTime, 0))
	res.UserList = make([]proto.IMUser, 0, len(userList))
	for _, user := range userList {
		res.UserList = append(res.UserList, proto.IMUser{
			Id:       user.ID,
			DepartId: user.DepartId,
			RealName: user.UserName,
		})
	}
}

func (s *Server) GetOnlineUser(req *proto.IMOnlineUserReq, res *proto.IMOnlineUserRes) {
	res.UserIdList = make([]uint, 0)
	for _, b := range s.Buckets {
		b.GetOnlineUser(res)
	}
}
